Skip to content

Make Java code model companion members static - #100

Merged
alexander-yevsyukov merged 3 commits into
masterfrom
claude/jvmstatic-companions-6a7371
Nov 2, 2026
Merged

alexander-yevsyukov merged 3 commits into
masterfrom
claude/jvmstatic-companions-6a7371

Conversation

@alexander-yevsyukov

Copy link
Copy Markdown
Contributor

What

This PR makes the caller-facing companion members of the Java code model in io.spine.tools.compiler.jvm callable from Java without .Companion, using @JvmStatic:

Before (Java) After (Java)
ClassName.Companion.guess(name) ClassName.guess(name)
ClassName.Companion.getSimpleNameRegex() ClassName.getSimpleNameRegex()
JavaTypeName.Companion.getKnownPrimitives() JavaTypeName.getKnownPrimitives()
TypeVariableName.Companion.getT() / getE() TypeVariableName.getT() / getE()
FieldMethods.Companion.getterOf(name, cardinality) FieldMethods.getterOf(name, cardinality)

@JvmStatic was chosen over @JvmField because it keeps the Companion accessors, so the change is binary- and source-compatible. javap on the built jar shows both the new static methods and the unchanged X$Companion methods. The ClassName.*_SEPARATOR constants are const val and were already static.

Why

core-jvm-compiler is replacing JavaPoet with the Compiler's Java code model. Its Java sources (FieldType and related classes) had to call ClassName.Companion.guess(...) and JavaTypeName.Companion.getKnownPrimitives(). This PR fixes that at the source.

Bug fix: JavaTypeName.KnownPrimitives could contain null

The list used to be built in the static initializer of JavaTypeName. Per JVMS §5.5, when a nested primitive object such as JavaTypeName.INT is initialized before JavaTypeName, the outer initializer reads INT.INSTANCE while it is still null. A fresh JVM produced [void, boolean, byte, short, null, long, char, float, double].

The list is now built by lazy. The public getters are unchanged; only a private backing field changed.

Tests

  • New XJavaSpec suites in jvm/src/test/java/ (ClassNameJavaSpec, JavaTypeNameJavaSpec, TypeVariableNameJavaSpec, FieldMethodsJavaSpec). They call each member both statically and through Companion.
  • A regression test in JavaTypeNameSpec runs a program in a fresh JVM (given/JvmRun.kt, given/PrimitiveFirstProgram.kt). The program touches INT first and checks the whole list. The test failed before the fix and passes after it. It uses ProcessBuilder rather than reflection, and passes the classpath via a manifest-only JAR so the command line stays short on Windows CI.

Reviewer notes

  • The copyright headers of the touched Kotlin files were rewritten to the CodeMatters header by the repo's update-copyright hook, which follows the profile switch in 537cd4e.
  • An unclosed code fence in the KDoc of ClassName.clazz is now closed, and TypeVariableName.T/E got KDoc.
  • Java can now also reach these statics through subclasses, e.g. EnumName.guess(...), which returns a ClassName. A Java subclass that declares an instance method with the same signature would no longer compile. No such subclasses exist in validation or core-jvm-compiler.
  • Out of scope: the companion members in the annotation/ and style/ sub-packages (SuppressWarningsAnnotation.ALL_WARNINGS, ModifiedTypeAnnotation.currentDateTime(), PsiJavaCodeStyleFormatter.settingsId).

Version

The version is bumped to 2.0.0-SNAPSHOT.083, and the dependency reports are regenerated. A clean ./gradlew build dokkaGenerate publishToMavenLocal passes locally.

🤖 Generated with Claude Code

alexander-yevsyukov and others added 3 commits November 2, 2026 22:32
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Annotate the caller-facing companion members of `ClassName`, `JavaTypeName`,
`TypeVariableName`, and `FieldMethods` with `@JvmStatic`, so that Java code
calls them as `ClassName.guess(...)`, `JavaTypeName.getKnownPrimitives()`,
etc. The `Companion` accessors remain, keeping the change binary- and
source-compatible.

Build `JavaTypeName.KnownPrimitives` lazily. It used to be computed in the
static initializer of `JavaTypeName`, which put `null` into the list when a
primitive type object, such as `JavaTypeName.INT`, was initialized before
`JavaTypeName` itself.

Add `XJavaSpec` suites for the Java access and a fresh-JVM regression test
for the initialization order.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings November 2, 2026 22:37
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 2, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-02T22:39:32.266506Z 581dd15 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approved

No active review issues are reported for the changes simplifying Java access to the compiler’s JVM code model.

No open issues 🎉

What changed in this PR

This PR simplifies Java access to the compiler’s JVM code model, supporting core-jvm-compiler’s migration from JavaPoet while retaining existing companion accessors.

Changes:

  • Adds @JvmStatic to caller-facing companion members and Java tests covering both access styles.
  • Lazily initializes known primitives to prevent null entries, with a fresh-JVM regression test.
  • Updates API documentation, bumps the version to 2.0.0-SNAPSHOT.083, and refreshes dependency reports.
File Description
version.gradle.kts Bumps the compiler snapshot version.
jvm/​src/​test/​kotlin/​io/​spine/​tools/​compiler/​jvm/​JavaTypeNameSpec.kt Adds the primitive-first initialization regression test.
jvm/​src/​test/​kotlin/​io/​spine/​tools/​compiler/​jvm/​given/​PrimitiveFirstProgram.kt Checks the primitive list after accessing INT first.
jvm/​src/​test/​kotlin/​io/​spine/​tools/​compiler/​jvm/​given/​JvmRun.kt Provides isolated JVM execution using a manifest classpath.
jvm/​src/​test/​java/​io/​spine/​tools/​compiler/​jvm/​TypeVariableNameJavaSpec.java Tests static and companion type-variable accessors.
jvm/​src/​test/​java/​io/​spine/​tools/​compiler/​jvm/​JavaTypeNameJavaSpec.java Tests static and companion primitive-list accessors.
jvm/​src/​test/​java/​io/​spine/​tools/​compiler/​jvm/​FieldMethodsJavaSpec.java Tests static and companion getter-name generation.
jvm/​src/​test/​java/​io/​spine/​tools/​compiler/​jvm/​ClassNameJavaSpec.java Tests Java access to factories, regex, and constants.
jvm/​src/​main/​kotlin/​io/​spine/​tools/​compiler/​jvm/​TypeVariableName.kt Exposes static getters for T and E and documents them.
jvm/​src/​main/​kotlin/​io/​spine/​tools/​compiler/​jvm/​JavaTypeName.kt Adds static primitive-list access and lazy initialization.
jvm/​src/​main/​kotlin/​io/​spine/​tools/​compiler/​jvm/​FieldConventions.kt Exposes getterOf() as a static Java method.
jvm/​src/​main/​kotlin/​io/​spine/​tools/​compiler/​jvm/​ClassName.kt Adds static companion access and closes a KDoc code fence.
docs/​dependencies/​pom.xml Updates the reported compiler version.
docs/​dependencies/​dependencies.md Refreshes report versions and generation timestamps.

Review effort: Balanced

@alexander-yevsyukov
alexander-yevsyukov merged commit 09f775b into master Nov 2, 2026
10 checks passed
@alexander-yevsyukov
alexander-yevsyukov deleted the claude/jvmstatic-companions-6a7371 branch November 2, 2026 23:01
@github-project-automation github-project-automation Bot moved this from In Review to ✅ Done in v2.0 Nov 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: ✅ Done

Development

Successfully merging this pull request may close these issues.

2 participants